#include <BootConsole.h>

int BootConsole::X, BootConsole::Y;
short *BootConsole::memPtr;

void BootConsole::Init()
{
	memPtr = (short *) 0xB8000;
	Clear(0x0F);
}

void BootConsole::Clear(char color)
{
	short val = ' ' | color << 8;
	for (int i = 0; i < 80 * 25; i++)
	{
		memPtr[i] = val;
	}
	X = Y = 0;
}

void BootConsole::Putc(char c)
{
	/* Output on the Bochs debugger console */
	asm volatile ("outb %%al, %%dx"
	:
	:"d" (0xE9), "a" (c));
	
	if (c == 0)
		return;
	else if (c == '\n')
	{
		X = 0;
		Y++;
		if (Y >= 25)
			Scroll();
		return;
	}
	
	memPtr[Y * 80 + X] = c | (memPtr[Y * 80 + X] & 0xFF00);
	X++;
	if (X >= 80)
	{
		X = 0;
		Y++;
		if (Y >= 25)
			Scroll();
	}
	
	return;
}

void BootConsole::Puts(const char *s)
{
	while (*s)
		Putc(*s++);
}

void BootConsole::Putn(unsigned long n)
{
	char buf[10];
	for (int i = 0; i < 10; i++)
		buf[i] = 0;
	
	if (n == 0)
	{
		Putc('0');
		return;
	}
	
	int cnt = 0;
	while (n)
	{
		buf[cnt++] = 0x30 + (n % 10);
		n /= 10;
	}
	
	cnt--;
	while (cnt >= 0)
	{
		Putc(buf[cnt--]);
	}
}

void BootConsole::Putx(unsigned long n)
{
	char buf[10];
	for (int i = 0; i < 10; i++)
		buf[i] = 0;
	
	if (n == 0)
	{
		Putc('0');
		return;
	}
	
	int cnt = 0;
	while (n)
	{
		if ((n % 16) > 9)
			buf[cnt++] = 'A' + ((n % 16) - 10);
		else
			buf[cnt++] = 0x30 + (n % 16);
		n /= 16;
	}
	
	cnt--;
	while (cnt >= 0)
	{
		Putc(buf[cnt--]);
	}
}

void BootConsole::Scroll()
{
	for (int i = 0; i < 24; i++)
	{
		for (int j = 0; j < 80; j++)
		{
			memPtr[i * 80 + j] = memPtr[(i + 1) * 80 + j];
		}
	}
	
	for (int i = 0; i < 80; i++)
		memPtr[80 * 24 + i] = 0x200F;
}
